﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Collections;
using System.Windows.Forms;
using System.Drawing.Imaging;
using System.IO;



namespace VisionEstereo.SegmentacionColores
{
    public partial class ResultadosSegmentacion
    {
        private System.Drawing.Bitmap disparidades, imagenFiltrada;
        private int disparidadMaxima;
        private int disparidadMedia;
        private App.TipoAlgoritmo tipoAlgoritmo;
        private bool segmentacion = false;
        private int[,] matrizClases;
        private ArrayList listaClases;
        private int ancho, alto;
        public PixelDato[] coloresClases;


        public ResultadosSegmentacion()
        {
            this.InitializeComponent();
           
        }
        public void setSegmentacionColores(bool b)
        {
            segmentacion = b;
        }

        public void setImagenResultado(BitmapSource resultado)
        {
            this.imgResultado.Source = resultado;           
        }

        public void setImagenInicial(System.Drawing.Bitmap bitmapInicial)
        {
            System.Windows.Media.Imaging.BitmapSource bitmapSource = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(bitmapInicial.GetHbitmap(), IntPtr.Zero, Int32Rect.Empty, System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions());
            this.imagenInicial.Source = bitmapSource;
        }

        public void setTipoAlgoritmo(App.TipoAlgoritmo tipoAlgoritmo)
        {
            this.tipoAlgoritmo = tipoAlgoritmo;
        }

        public void setColoresClases(System.Drawing.Bitmap Result)
        {
            Clase obj;
            int cont = 0;
            coloresClases = new PixelDato[listaClases.Count];
            IEnumerator objMyEnum = listaClases.GetEnumerator();
            while (objMyEnum.MoveNext())
            {
                obj = (Clase)objMyEnum.Current;
                this.coloresClases[cont] = obj.getCentro();
                cont++;
            }

            /* LEYENDA DE CLASES */
            IEnumerator iteradorLista = listaClases.GetEnumerator();
            int i = 1;
       
            while (iteradorLista.MoveNext())
            {
                Clase clase = (Clase)iteradorLista.Current;
                PixelDato centro = clase.getCentro(); //habrá que extraer el RGB y meterlo en un Brush
                Rectangle cuad = new Rectangle();
                int marginTop =  40 * (i - 1); 
                int marginLeft = 0 ;
                if(i>1) marginLeft = -40;
                cuad.Margin = new Thickness(marginLeft, marginTop, 0, 0);
                cuad.Stroke = Brushes.Black;
                cuad.VerticalAlignment = VerticalAlignment.Top;
                cuad.Width = 40;
                cuad.Height = 30;

                SolidColorBrush myBrush = new SolidColorBrush();
                myBrush.Color = Color.FromRgb(centro.Red, centro.Green, centro.Blue);
                cuad.Fill = myBrush;
                this.PanelClases.Children.Add(cuad);

                System.Windows.Controls.Label iClase = new System.Windows.Controls.Label();
                iClase.Content = i;
                iClase.Margin = new Thickness(-40, marginTop, 0, 0);
                this.PanelClases.Children.Add(iClase);
                i++;
            }
        }


        /// <summary>
        /// Este método almacena un Bitmap de disparidades, para
        /// poder visualizar los datos al hacer clic sobre cada píxel.
        /// </summary>
        /// <param name="disparidades">Matriz de disparidades</param>
        public void setImagenDisparidades(System.Drawing.Bitmap disparidades)
        {
            this.disparidades = disparidades;
        }
        //----copiamos matriz de clases--------//
        public void setImagenClases(int[,] m)
        {
            this.matrizClases = m;
        }
        ///------------------------Poner etiqueta Numero de clases-------------------------------------///
        public void setNumeroClases(int n)
        {
            this.labelClases.Content = String.Format("Numero de clases: {0}", n);
        }
        public void setListaClases(ArrayList lista)
        {
            this.listaClases = lista;
        }
        public void setTiempo(String tiempo)
        {
            this.labelTime.Content = "Tiempo: " + tiempo;
        }
        private void setLabelCoordenadas(Point punto)
        {
            int x = (int) punto.X;
            int y = (int) punto.Y;
            this.labelCoordenadas.Content = String.Format("Coordenadas: X = {0} Y = {1}", x, y);
        }

        private void setLabelDisparidad(int disparidad)
        {
            this.labelDisparidad.Content = String.Format("Disparidad: {0}", disparidad);
        }
        //------------------------Poner etiqueta Clase para la segmentación--------------///
        private void setLabelSegmentacion(int seg)
        {
            this.labelDisparidad.Content = String.Format("Clase: {0}", seg);
        }


        public void setDisparidadesMaximaYMedia(int disparidadMaxima, int disparidadMedia)
        {
            this.disparidadMaxima = disparidadMaxima;
            this.disparidadMedia = disparidadMedia;
            labelDisparidad.Content = String.Format("Disparidad máxima: {0} Disparidad media: {1}", disparidadMaxima, disparidadMedia);
        }

        private void botonHome_Click(object sender, System.Windows.RoutedEventArgs e)
        {
            PantallaInicial pagInicio = new PantallaInicial();
            this.NavigationService.Navigate(pagInicio);
        }

        private void imgResultado_MouseMove(object sender, System.Windows.Input.MouseEventArgs e)
        {
            setLabelCoordenadas(e.GetPosition(imgResultado));
        }

        public void setTamañoImagenReal(int x, int y)
        {
            ancho = x;
            alto = y;
        }


        private void imgResultado_MouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            ///--------------segmentación----------------///
            if (segmentacion == true)
            {
                int x = (int)e.GetPosition(imgResultado).X;
                int y = (int)e.GetPosition(imgResultado).Y;

                int with = (int)((x * ancho) / imgResultado.ActualWidth);
                int height = (int)((y * alto) / imgResultado.ActualHeight);

                int ClaseN = (int)matrizClases.GetValue(with, height);
                setLabelSegmentacion(ClaseN);
            }
            //----------------------------------------------------//
            else if (!tipoAlgoritmo.Equals(App.TipoAlgoritmo.Anaglifo) && !tipoAlgoritmo.Equals(App.TipoAlgoritmo.DeteccionObjetos))
            {
                // En el anaglifo y la detección de objetos no debemos responder a los clic
                int x = (int)e.GetPosition(imgResultado).X;
                int y = (int)e.GetPosition(imgResultado).Y;
                setLabelDisparidad(disparidades.GetPixel(x, y).R);
            }

        }
        
        private void BotonGuardar_Click(object sender, RoutedEventArgs e)
        {
            SaveFileDialog dialogoGuardar = new SaveFileDialog();
            dialogoGuardar.Filter = "Archivos de imagen|*.jpg;*.png;*.bmp";
            dialogoGuardar.Title = "Elija dónde guardar su imagen";

            if (dialogoGuardar.ShowDialog() == DialogResult.OK && dialogoGuardar.FileName != "")
            {
                //guaradamos bitMap
                BitmapSource bitmap = imgResultado.Source as BitmapSource;
                if (bitmap != null)
                {
                    JpegBitmapEncoder jpeg = new JpegBitmapEncoder();
                    jpeg.Frames.Add(BitmapFrame.Create(bitmap));
                    using (Stream stm = File.Create(dialogoGuardar.FileName))
                    {
                        jpeg.Save(stm);
                    }
                }
                //guardamos matrizClases
                int dimx = (int)this.imgResultado.Source.Width;
                int dimy = (int)this.imgResultado.Source.Height;
                char[] myChar = {'.','j','p','g'};
                string nombreFich = dialogoGuardar.FileName.TrimEnd(myChar);
                StreamWriter fichero = new StreamWriter(nombreFich+ "_mapaClases.txt");
            
                for (int i = 0; i < dimx; i++)
                {
                    for (int j = 0; j < dimy; j++)
                    {
                        fichero.WriteLine(this.matrizClases[i,j]);                          
                    }
                }
                fichero.Close();
            }
        }


        int max(int a, int b) { if (a > b) return a; return b; }
        int min(int a, int b) { if (a < b) return a; return b; }

        private void BotonFiltro_Click(object sender, RoutedEventArgs e)
        {
            int dimx, dimy;
            int idx, ign;
            int i, j, k, l, m, cl, cu, rl, ru, mode;
            double[] pen;
            double penmax;

            ElegirFiltro ventanaFiltro = new ElegirFiltro();
            if (ventanaFiltro.ShowDialog() == true)
            {

                int tam = Int32.Parse(ventanaFiltro.tamVentanaBox.Text);

                dimx = (int)this.imgResultado.Source.Width;
                dimy = (int)this.imgResultado.Source.Height;


                int[,] matrizSalida = new int[dimx, dimy];
                int[] win = new int[2];


                pen = new double[256];

                ign = 0;
                win[0] = tam;
                win[1] = tam;

                for (i = 0; i < dimx; i++)        // for every pixel
                {
                    for (j = 0; j < dimy; j++)
                    {
                        for (m = 0; m < 256; m++) pen[m] = 0;  // zero out bins    //TODO:poner tam a nº de clases
                        mode = 0; penmax = 0;          // clear mode and max bin count

                        rl = max(0, i - win[0]);          // set up local windows
                        ru = min((int)dimx, i + win[0]);
                        cl = max(0, j - win[1]);
                        cu = min((int)dimy, j + win[1]);

                        for (k = rl; k < ru; k++)             // for every pixel in local window
                        {
                            for (l = cl; l < cu; l++)
                            {
                                idx = this.matrizClases[k, l];  // get bin number

                                if (idx < ign) continue;      // assume bad pixels if below ign

                                pen[idx]++;                // increment bin count
                                if (pen[idx] > penmax)       // if its a new mode
                                {
                                    penmax = pen[idx];    // update bin count max
                                    mode = idx;            // update mode
                                }
                            }
                        }
                        matrizSalida[i, j] = mode;              // set output pixel to mode from window
                    }
                }
                //dibujar nueva matriz
                imagenFiltrada = new System.Drawing.Bitmap((int)this.imgResultado.Source.Width, (int)this.imgResultado.Source.Height);

                for (i = 0; i < dimx; i++)
                {
                    for (j = 0; j < dimy; j++)
                    {
                        PixelDato p = coloresClases[matrizSalida[i, j] - 1];
                        System.Drawing.Color color_aux = System.Drawing.Color.FromArgb(p.Red, p.Green, p.Blue);
                        imagenFiltrada.SetPixel(i, j, color_aux);
                    }
                }
                //meter Bitmap a la imagen
                System.Windows.Media.Imaging.BitmapSource bitmapSource = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(imagenFiltrada.GetHbitmap(), IntPtr.Zero, Int32Rect.Empty, System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions());
                setImagenResultado(bitmapSource);

            }
            
        }

        private void FrameClases_Navigated(object sender, System.Windows.Navigation.NavigationEventArgs e)
        {

            IEnumerator iteradorLista = listaClases.GetEnumerator();
            int i = 1;
            while (iteradorLista.MoveNext())
            {
                Clase clase = (Clase)iteradorLista.Current;
                PixelDato centro = clase.getCentro(); //habrá que extraer el RGB y meterlo en un Brush

                Rectangle cuad = new Rectangle();
                double marginTop = 50 + 40 * (i - 1);
                cuad.Margin = new Thickness(40, marginTop, 0, 0);
                cuad.Stroke = Brushes.Black;
                cuad.VerticalAlignment = VerticalAlignment.Top;
                cuad.Width = 40;
                cuad.Height = 30;

                SolidColorBrush myBrush = new SolidColorBrush();
                myBrush.Color = Color.FromRgb(centro.Red, centro.Green, centro.Blue);
                cuad.Fill = myBrush;

                this.LayoutRoot.Children.Add(cuad);

                i++;
            }
        }
    }
}




